package de.koller.oceanFramework.gl.util;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.ARBFragmentShader;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.ARBVertexShader;

public class OceanShader {

	private final IOceanShaderProgram program;
	
	private int shader;
	private int fragShader;
	private int vertShader;
	
	public static OceanShader createShader( IOceanShaderProgram program ) {
		return new OceanShader( program );
	}
	
	private OceanShader( IOceanShaderProgram program ) {
		this.program = program;
		
		shader = ARBShaderObjects.glCreateProgramObjectARB();
		createFragShader();
		createVertShader();
		
		if( vertShader != 0 )
			ARBShaderObjects.glAttachObjectARB( shader, vertShader );
		if( fragShader != 0 )
			ARBShaderObjects.glAttachObjectARB( shader, fragShader );
		
		ARBShaderObjects.glLinkProgramARB( shader );
		ARBShaderObjects.glValidateProgramARB( shader );
		
		checkLog( shader );
	}
	
	private void createFragShader() {
		String code = program.getFragmentShader();
		if( code == null )
			return;
		
		fragShader = ARBShaderObjects.glCreateShaderObjectARB( ARBFragmentShader.GL_FRAGMENT_SHADER_ARB );
		ARBShaderObjects.glShaderSourceARB( fragShader, code );
		ARBShaderObjects.glCompileShaderARB( fragShader );
		checkLog( fragShader );
	}
	
	private void createVertShader() {
		String code = program.getVertexShader();
		if( code == null )
			return;
		
		vertShader = ARBShaderObjects.glCreateShaderObjectARB( ARBVertexShader.GL_VERTEX_SHADER_ARB );
		ARBShaderObjects.glShaderSourceARB( vertShader, code );
		ARBShaderObjects.glCompileShaderARB( vertShader );
		checkLog( vertShader );
	}
	
	private void checkLog( int shader ) {
		IntBuffer iVal = BufferUtils.createIntBuffer(1);
		ARBShaderObjects.glGetObjectParameterARB( shader, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal );
		
		int length = iVal.get();
		if (length > 1) {
			ByteBuffer infoLog = BufferUtils.createByteBuffer( length );
			iVal.flip();
			ARBShaderObjects.glGetInfoLogARB( shader, iVal, infoLog );
			byte[] infoBytes = new byte[ length ];
			infoLog.get( infoBytes );
			String out = new String( infoBytes );
			System.err.println( program.toString() + ": " + out );
		}
	}
	
	public void useShader() {
		ARBShaderObjects.glUseProgramObjectARB( shader );
	}
	
	public void unuseShader() {
		ARBShaderObjects.glUseProgramObjectARB(0);
	}
	
	public int getProgramID() {
		return shader;
	}
	
}
